/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.servinf.ani.mapper;

import com.servinf.ani.sincronizador.App;
import com.servinf.ani.sincronizador.entities.Concesion;
import com.servinf.ani.sincronizador.entities.Departamento;
import com.servinf.ani.sincronizador.entities.EstadoIniciativa;
import com.servinf.ani.sincronizador.entities.ModoTransporte;
import com.servinf.ani.sincronizador.entities.Proyecto;
import com.servinf.ani.sincronizador.entities.ProyectosXDepartamento;
import com.servinf.ani.sincronizador.entities.ProyectosXDepartamentoPK;
import com.servinf.ani.sincronizador.entities.SubEstadosParaProyectos;
import com.servinf.ani.sincronizador.entities.TipoInicitativa;
import com.servinf.ani.sincronizador.entities.TipoProyecto;
import com.servinf.ani.sincronizador.exception.DifferentLengthException;
import com.servinf.ani.sincronizador.exception.IncompatibleTypesException;
import com.servinf.ani.sincronizador.exception.NonExistentValue;
import com.servinf.ani.sincronizador.utils.LogHelper;
import com.servinf.ani.sincronizador.utils.RelationMaps;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.poi.ss.usermodel.DateUtil;

/**
 *
 * @author mortiz
 */
public class ProjectMapper {
    
    //Indices de los campos en el archivo excel
    public static final int  IdDelProyecto = 0 ;
    public static final int  NombreDelTipoDeProyectoEmpresarial = 1 ;
    public static final int  NombreDeProyecto = 2 ;
    public static final int  EstadodelProyecto = 3 ;
    public static final int  GeneracióndelContrato = 4 ;
    public static final int  InversionEstimada = 5 ;
    public static final int  Capex = 6 ;
    public static final int  Opex = 7 ;
    public static final int  IdDelPropietarioDelProyecto = 8 ;
    public static final int  NombreDelPropietarioDelProyecto = 9 ;
    public static final int  PlazoConcesión = 10 ;
    public static final int  Empleosdirectosgenerados = 11 ;
    public static final int  Empleosindirectosgenerados = 12 ;
    public static final int  Longitudinicialconcesionada = 13 ;
    public static final int  Longitudadicionalconcesionada = 14 ;
    public static final int  ValorinicialdelContratodeconcesión = 15 ;
    public static final int  Valormodificacionesdelcontratodeconcesión = 16 ;
    public static final int  Festimadodeterminación = 17 ;
    public static final int  DeudaANIEstimadasporConcesión = 18 ;
    public static final int  PlazoEtapaPreconstrucción = 19 ;
    public static final int  PlazoEtapaConstrucción = 20 ;
    public static final int  PlazoEtapaOperaciónyMantenimiento = 21 ;
    public static final int  DobleCalzadaKm = 22 ;
    public static final int  CalzadasencillaKm = 23 ;
    public static final int  MejoramientoKm = 24 ;
    public static final int  RehabilitaciónKm = 25 ;
    public static final int  OperaciónyMantenimientoKm = 26 ;
    public static final int  InvCalzadaSencilla = 27 ;
    public static final int  InvDobleCalzada = 28 ;
    public static final int  InvSegundaCalzada = 29 ;
    public static final int  InvMejoramiento = 30 ;
    public static final int  InvRehabilitacion = 31 ;
    public static final int  FechaFinalizaciónOperaciónyMantenimiento = 32 ;
    public static final int  FechadeReversión = 33 ;
    public static final int  FechadelActadeLiquidación = 34 ;
    public static final int  FechadelActadelrecibofinal = 35 ;
    public static final int  GerenteGestiónContractual = 36 ;
    public static final int  Constantesdelaño = 37 ;
    public static final int  DepartamentoProyecto = 38 ;
    public static final int  InversionDpto = 39 ;
    public static final int  KmporDpto = 40 ;
    public static final int  FechadeInicioLicitación = 41 ;
    public static final int  FechaInicioAdjudicación = 42 ;
    public static final int  TipoIniciativa = 43 ;


    private static String currentField;
    
    public static Proyecto excelToProject(List<Object> excelRow, Proyecto project) throws IncompatibleTypesException {
        try {
            boolean isCreating = false;
            /*** Mapeo del proyecto ***/
            if(project == null)  {
                project = new Proyecto();
                isCreating = true;
                //project.setIdProyecto(new Integer(0));
            }
            currentField = "IdDelProyecto";
            project.setIdEnProject((String)excelRow.get(IdDelProyecto));
            currentField = "NombreDeProyecto";
            project.setNombre((String)excelRow.get(NombreDeProyecto));
            /** Inicio de mapeo de las relaciones  **/

            SimpleDateFormat format = new SimpleDateFormat(App.getDateFormatString());
            /* Forma de almacenar dechas
            if(excelRow.get(Festimadodeterminación) != null) {
                currentField = "Festimadodeterminación";
                Double dateNumeric = (Double) excelRow.get(Festimadodeterminación);
                Date date = DateUtil.getJavaDate(dateNumeric);
                project.getConcesionList().get(0).setFechaActaInicio(date);
            }*/
            
            if(excelRow.get(GeneracióndelContrato) != null)  {
                currentField = "GeneracióndelContrato";
                String value = (String) excelRow.get(GeneracióndelContrato);
                Integer typeId = RelationMaps.getInstance().getProjectTypesMap().get(value);
                if(typeId == null) {
                    //throw new NonExistentValue(value); //Se lannza cuando no se encuentra el tipo de proyecto
                   //Ahora en excel puede llegar Primera y Segunda generacín, lo caul no está en BD, asi que se asignan a tercera.
                   typeId = RelationMaps.getInstance().getProjectTypesMap().get("Tercera Generación");
                } 
                project.setTipoProyecto(new TipoProyecto(typeId));
            }

            if(excelRow.get(TipoIniciativa) != null)  {
                currentField = "TipoIniciativa";
                String value = (String) excelRow.get(TipoIniciativa);
                String initiativeType;
                try {
                    initiativeType = value.substring(0, value.indexOf(".")); //En el excel se espera Privada.Prefactibilidad Aprobada o Pública
                    String feasibilityState = value.substring(value.indexOf(".") + 1); //Estado de factibilidad
                    Integer initiativeTypeId = RelationMaps.getInstance().getInitiativeTypeMap().get(initiativeType); //Id del tipo de iniciativa
                    Integer feasibilityStateId = RelationMaps.getInstance().getInitiativeStateMap().get(feasibilityState); //Id del estado de factibiliadad
                    //Si el tipo de iniciativa o el estado de factibilidad es nulo, no se crea/actualiza.
                    if(initiativeTypeId == null || feasibilityStateId == null)  {
                        throw new NonExistentValue(initiativeType + "." + feasibilityState);
                    }else {
                        project.setTipoIniciativa(new TipoInicitativa(initiativeTypeId));
                        project.setEstadoIniciativa(new EstadoIniciativa(feasibilityStateId));
                    }
                }
                catch(StringIndexOutOfBoundsException e){ //Excepción que ocurre cuando no se se encuentra el '.' en el excel
                    //Cuando viene solamente un valor normalmente Pública
                    initiativeType = value;
                    Integer initiativeTypeId = RelationMaps.getInstance().getInitiativeTypeMap().get(initiativeType); //Id del tipo de iniciativa
                    if(initiativeTypeId == null)  {
                        throw new NonExistentValue(initiativeType);
                    }else {
                        project.setTipoIniciativa(new TipoInicitativa(initiativeTypeId));
                    }
                }
                
            }

             /** Estado del proyecto  **/
            if(excelRow.get(EstadodelProyecto) != null)  {
                currentField = "EstadodelProyecto";
                String excelValue = (String) excelRow.get(EstadodelProyecto);
                if(excelValue.contains("Gestión Contractual.")) {
                    excelValue = excelValue.substring(excelValue.indexOf(".") + 1);
                }
                Integer stateId = RelationMaps.getInstance().getStatesMap().get(excelValue);
                if(stateId == null) {
                    throw new NonExistentValue(excelValue);
                }
                SubEstadosParaProyectos state = new SubEstadosParaProyectos(stateId);
                //SubEstadosParaProyectos state1 = new SubEstadosParaProyectos(3); //En caso de tener más estados, esta la forma de agregarlo.
                List estados = new ArrayList<SubEstadosParaProyectos>();
                estados.add(state);
                //estados.add(state1);
                project.setSubEstadosParaProyectosList(estados);
            }

            if(excelRow.get(Capex) != null) {
                currentField = "Capex";
                if(excelRow.get(Capex) instanceof String) {
                    String capexString = (String) excelRow.get(Capex);
                    project.setCapex(Double.parseDouble(capexString));
                }else {
                    project.setCapex(((Double)excelRow.get(Capex)));
                }
                
            }
            if(excelRow.get(Opex) != null) { 
                if(excelRow.get(Opex) instanceof String) {
                    String opexString = (String) excelRow.get(Opex);
                    project.setOpex(Double.parseDouble(opexString));
                }else {
                    project.setOpex(((Double)excelRow.get(Opex)));
                }
            }
            
            if(excelRow.get(InversionEstimada) != null) { 
                currentField = "Inversion estimada";
                project.setInversionEstimada(((Double)excelRow.get(InversionEstimada)));
            }

            if(excelRow.get(Constantesdelaño) != null) {
                currentField = "Constantesdelaño";
                project.setPreciosConstante(Double.parseDouble((String)excelRow.get(Constantesdelaño)));
            }
            
            if(excelRow.get(PlazoEtapaConstrucción) != null) {
                currentField = "PlazoEtapaConstrucción";
                project.setDuracionEjecConstr(((Double) excelRow.get(PlazoEtapaConstrucción)).intValue());
            }
            //De momento todos el proyecto solo considera proyectos de tipo carretero, 1=id carretero
            project.setModoTransporte(new ModoTransporte(1));  

            if(isCreating) {
                return project;
            }

            /** Mapeo en la tabla de concesiones **/

            if(project.getConcesionList() == null) {
                project.setConcesionList(new ArrayList<Concesion>());
                project.getConcesionList().add(new Concesion()); 
                project.getConcesionList().get(0).setIdProyecto(new Proyecto(project.getIdProyecto()));
            }
            //Puede llegar la concesión no nula pero vacía
            if(project.getConcesionList().isEmpty()) {
                project.getConcesionList().add(new Concesion());  
                project.getConcesionList().get(0).setIdProyecto(new Proyecto(project.getIdProyecto()));
            }
            
            if(excelRow.get(PlazoConcesión) != null) {
                currentField = "PlazoConcesión";
                Double value = (Double) excelRow.get(PlazoConcesión);
                project.getConcesionList().get(0).setPlazoConcesion(value);
            }
            
             if(excelRow.get(Longitudinicialconcesionada) != null) {
                currentField = "Longitudinicialconcesionada";
                Double value = (Double) excelRow.get(Longitudinicialconcesionada);
                project.getConcesionList().get(0).setLongitudInicial(value);
            }
            
             if(excelRow.get(Longitudadicionalconcesionada) != null) {
                currentField = "Longitudadicionalconcesionada";
                Double value = (Double) excelRow.get(Longitudadicionalconcesionada);
                project.getConcesionList().get(0).setLongitudAdicional(value);
            } 
            
             
            if(excelRow.get(ValorinicialdelContratodeconcesión) != null) {
                currentField = "ValorinicialdelContratodeconcesión";
                Double value = (Double) excelRow.get(ValorinicialdelContratodeconcesión);
                project.getConcesionList().get(0).setValorInicial(value);
            }

            if(excelRow.get(FechaFinalizaciónOperaciónyMantenimiento) != null) {
                currentField = "FechaFinalizaciónOperaciónyMantenimiento";
                Date date = format.parse((String) excelRow.get(FechaFinalizaciónOperaciónyMantenimiento));
                project.getConcesionList().get(0).setFechaFinOperacionMantenimiento(date);
            }
            
            //Fechas de reversión
            if(excelRow.get(FechadeReversión) != null) {
                currentField = "FechadeReversión";
                Date date = format.parse((String) excelRow.get(FechadeReversión));
                project.getConcesionList().get(0).setFechaReversion(date);
            }
            
            if(excelRow.get(FechadelActadeLiquidación) != null) {
                currentField = "FechadelActadeLiquidación";
                Date date = format.parse((String) excelRow.get(FechadelActadeLiquidación));
                project.getConcesionList().get(0).setFechaActaLiquidacion(date);
            }
            
            if(excelRow.get(FechadelActadelrecibofinal) != null) {
                currentField = "FechadelActadelrecibofinal";
                Date date = format.parse((String) excelRow.get(FechadelActadelrecibofinal));
                project.getConcesionList().get(0).setFechaActaReciboFinal(date);
            }
            
            if(excelRow.get(FechadeInicioLicitación) != null) {
                currentField = "FechadeInicioLicitación";
                Date date = format.parse((String) excelRow.get(FechadeInicioLicitación));
                project.getConcesionList().get(0).setFechaInicioLicitacion(date);
            }
            
            if(excelRow.get(FechaInicioAdjudicación) != null) {
                currentField = "FechaInicioAdjudicación";
                Date date = format.parse((String) excelRow.get(FechaInicioAdjudicación));
                project.getConcesionList().get(0).setFechaAdjudicacion(date);
            }
            
            String nombreConcession = App.concessionsMap.get((String)excelRow.get(IdDelProyecto));
            if(nombreConcession != null) {
                currentField = "Nombre_Concesionario";
                project.getConcesionList().get(0).setNombreConcesionario(nombreConcession);
            }
            
            /*
            // Fechas que estaban presentes en versiones anteriores del Excel, y ahora no, sin embargo, permanecen en BD
            if(excelRow.get(FdelActadeInicio) != null) {
                currentField = "FdelActadeInicio";
                Date date = format.parse((String) excelRow.get(FdelActadeInicio));
                project.getConcesionList().get(0).setFechaActaInicio(date);
            }
            if(excelRow.get(Festimadodeterminacion) != null) {
                currentField = "Festimadodeterminacion";
                Date date = format.parse((String) excelRow.get(Festimadodeterminacion));
                project.getConcesionList().get(0).setFechaEstimadaTerminacion(date);
            }
            if(excelRow.get(Fechafindeconstruccion) != null) {
                currentField = "Fechafindeconstruccion";
                Date date = format.parse((String) excelRow.get(Fechafindeconstruccion));
                project.getConcesionList().get(0).setFechaFinConstruccion(date);
            }
            if(excelRow.get(FechaFinalizacionOperacionyMantenimiento) != null) {
                currentField = "FechaFinalizacionOperacionyMantenimiento";
                Date date = format.parse((String) excelRow.get(FechaFinalizacionOperacionyMantenimiento));
                project.getConcesionList().get(0).setFechaFinOperacionMantenimiento(date);
            }
            if(excelRow.get(FFinalizacionEtapaPreConst) != null) {
                currentField = "FFinalizacionEtapaPreConst";
                Date date = format.parse((String) excelRow.get(FFinalizacionEtapaPreConst));
                project.getConcesionList().get(0).setFechaFinPreconstruccion(date);
            }
            if(excelRow.get(Fechadeinicioconstruccion) != null) {
                currentField = "Fechadeinicioconstruccion";
                Date date = format.parse((String) excelRow.get(Fechadeinicioconstruccion));
                project.getConcesionList().get(0).setFechaInicioContruccion(date);
            }
            if(excelRow.get(FdeActadeInicioPreConst) != null) {
                currentField = "FdeActadeInicioPreConst";
                Date date = format.parse((String) excelRow.get(FdeActadeInicioPreConst));
                project.getConcesionList().get(0).setFechaInicioPrecontruccion(date);
            }
            if(excelRow.get(FechadeSuscripcionConcesion) != null) {
                currentField = "FechadeSuscripcionConcesion";
                Date date = format.parse((String) excelRow.get(FechadeSuscripcionConcesion));
                project.getConcesionList().get(0).setFechaSuscripcion(date);
            }*/
           
           
            
            if(excelRow.get(DepartamentoProyecto) != null) {
                currentField = "DepartamentoProyecto";
                String[] departments = ((String) excelRow.get(DepartamentoProyecto)).split(",");
                List<ProyectosXDepartamento> infoByDepartment = new ArrayList<ProyectosXDepartamento>();
                for(String departmentString : departments) {
                    Integer departmentId = RelationMaps.getInstance().getDepartmentMap().get(departmentString.trim());
                    if(departmentId == null) {
                        throw new NonExistentValue(departmentString);
                    }
                    ProyectosXDepartamento proyectosXDepartamento = new ProyectosXDepartamento();
                    if(project.getIdProyecto() != null) 
                        proyectosXDepartamento.setProyectosXDepartamentoPK(new ProyectosXDepartamentoPK(project.getIdProyecto(), departmentId));
                    else 
                        proyectosXDepartamento.setDepartamento(new Departamento(departmentId));
                    infoByDepartment.add(proyectosXDepartamento);
                }
                if(excelRow.get(InversionDpto) != null)  {
                    currentField = "InversionDpto";
                    //Se hace el replace porque se están recibiendo archivos con este campo de la forma: <p>​114102, 685510</p>
                    String readedValue = (String) excelRow.get(InversionDpto);
                    int endOfFirstTag = readedValue.indexOf(">") + 2;
                    int startOfEndTag = readedValue.indexOf("<", endOfFirstTag);
                    String withoutTag = readedValue.substring(endOfFirstTag, startOfEndTag);
                    String[] investmentByDepartments = withoutTag.split(",");
                    if(departments.length == investmentByDepartments.length) {
                        int i = 0;
                        for(String investmentByDepartment : investmentByDepartments) {
                            String value = investmentByDepartment.trim();
                            Double investment = Double.parseDouble(value);
                            ProyectosXDepartamento proyectosXDepartamento = infoByDepartment.get(i);
                            proyectosXDepartamento.setInversion(investment);
                            i++;
                        }
                    }else{
                        throw new DifferentLengthException("El número de elementos por departamento en Inversión es diferente al número de departamentos Id Proyecto -> " 
                                + project.getIdEnProject());
                    }
                }
                if(excelRow.get(KmporDpto) != null)  {
                    currentField = "KmporDpto";
                    String readedValue = (String) excelRow.get(KmporDpto);
                    int endOfFirstTag = readedValue.indexOf(">") + 2;
                    int startOfEndTag = readedValue.indexOf("<", endOfFirstTag);
                    String withoutTag = readedValue.substring(endOfFirstTag, startOfEndTag);
                    String[] kmByDepartments =  withoutTag.split(",");
                    if(departments.length == kmByDepartments.length) {
                        int i = 0;
                        for(String kmByDepartment : kmByDepartments) {
                            //String value = kmByDepartment.trim().replaceAll("\\.", ",");
                            String value = kmByDepartment.trim();
                            Double km = Double.parseDouble(value);
                            ProyectosXDepartamento proyectosXDepartamento = infoByDepartment.get(i);
                            proyectosXDepartamento.setKilometros(km);
                            i++;
                        }
                    }else{
                        throw new DifferentLengthException("El número de elementos por departamento en Kilómetros es diferente al número de departamentos Id Proyecto -> " 
                                + project.getIdEnProject());
                    }
                }
                project.setProyectosXDepartamentoList(infoByDepartment);
            }
            return project;
        }
        catch(ParseException pe) {
            throw new IncompatibleTypesException("Error de lectura de fechas en el campo " + currentField + " : " + pe.getMessage() + " Id Proyecto -> " 
                                + project.getIdEnProject());
        }
        catch(ClassCastException ce) {
            throw new IncompatibleTypesException("Error de conversión de tipos en el campo " + currentField + " : " + ce.getMessage() + "Id Proyecto -> " 
                                + project.getIdEnProject());
        }catch(NonExistentValue ne) {
            try {
                LogHelper.Log(LogHelper.ERROR, "En excel viene un valor como llave que no se puede resolver en BD para el campo " + currentField + "Id Proyecto -> " 
                                + project.getIdEnProject(), ne);
            } catch (IOException ex) {
                Logger.getLogger(ProjectMapper.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        catch(DifferentLengthException e) {
            try {
                LogHelper.Log(LogHelper.ERROR, "Longitudes diferentes en información de departamentos " + currentField + "Id Proyecto -> " 
                                + project.getIdEnProject(), e);
            } catch (IOException ex) {
                Logger.getLogger(ProjectMapper.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return null;
        
    }
    
}
